<template>
  <div
    class="gb-ant-select-multiple-cascader"
    :class="{ 'multiple-cascader-outside': !isClickOutSide }"
    v-clickoutside="handleDropDownOutSide"
  >
    <a-select
      v-bind="$attrs"
      v-on="$listeners"
      mode="multiple"
      :maxTagTextLength="maxTagTextLength"
      :maxTagCount="maxTagCount"
      style="width:100%"
      :placeholder="placeholder"
      :value="selectedValueArr"
      :notFoundContent="null"
      :open="isOpen"
      showArrow
      :allowClear="allowClear"
      optionLabelProp="text"
      :dropdownMatchSelectWidth="false"
      :getPopupContainer="tirggerNode => tirggerNode.parentNode"
      @focus="handleFocus"
      @deselect="handleDeselect"
    >
      <a-icon
        type="close-circle"
        slot="clearIcon"
        theme="filled"
        @click="handleClearAll"
      />
      <template slot="dropdownRender" slot-scope="menu">
        <v-nodes :vnodes="menu" />
        <div :class="dropdownClassName">
          <div class="cascader-not-content" v-if="treeDataList.length <= 0">
            <a-empty :image="simpleImage" :description="noDataText"></a-empty>
          </div>
          <div class="cascader-content-wrap" v-else>
            <div class="cascader-content-container">
              <ul
                class="cascader-content-list"
                v-for="(itemList, levelIndex) in treeDataList"
                :key="levelIndex"
              >
                <li
                  class="cascader-content-item cascader-content-item-check-all"
                  @click="handleCascaderAllItemClick(isCheckAll)"
                  v-if="levelIndex === 0"
                >
                  <a-checkbox
                    :indeterminate="isIndeterminateAll"
                    v-model="isCheckAll"
                  />
                  <span class="checkbox-text">{{ allText }}</span>
                </li>
                <li
                  class="cascader-content-item"
                  v-for="(subItem, subIndex) in itemList"
                  :key="subItem[selectOptionsConfig.key]"
                  :title="subItem[selectOptionsConfig.text]"
                  :class="{ 'cascader-content-item-active': subItem.$active }"
                  @click="
                    handleCascaderItemClick(subItem, subIndex, levelIndex)
                  "
                >
                  <a-checkbox
                    :indeterminate="!!subItem.$indeterminate"
                    :checked="!!subItem.$checked"
                    @click.self="
                      e => handleCheckClick(e, subItem, subIndex, levelIndex)
                    "
                  />
                  <span class="checkbox-text">{{
                    subItem[selectOptionsConfig.text]
                  }}</span>
                  <a-icon
                    type="right"
                    style="font-size:10px;"
                    v-if="
                      subItem[selectOptionsConfig.children] &&
                        subItem[selectOptionsConfig.children].length > 0
                    "
                  />
                </li>
              </ul>
            </div>
          </div>
        </div>
      </template>
      <a-select-option
        v-for="item in treeToList"
        :key="item[selectOptionsConfig.key]"
        :value="item[selectOptionsConfig.value]"
        :text="item[selectOptionsConfig.text]"
      >
        {{ item[selectOptionsConfig.text] }}
      </a-select-option>
    </a-select>
  </div>
</template>

<script>
import { Empty } from "ant-design-vue";
import { cloneDeep } from "lodash";
const clickoutside = {
  // 初始化指令
  bind(el, binding) {
    function documentHandler(e) {
      if (el.contains(e.target)) {
        return false;
      }
      if (binding.expression) {
        binding.value(e);
      }
    }
    el.__vueClickOutside__ = documentHandler;
    document.addEventListener("click", documentHandler);
  },
  update() {},
  unbind(el) {
    document.removeEventListener("click", el.__vueClickOutside__);
    delete el.__vueClickOutside__;
  }
};
export default {
  name: "gbAntSelectMultipleCascader",
  components: {
    VNodes: {
      functional: true,
      render: (h, ctx) => {
        return ctx.props.vnodes;
      }
    }
  },
  directives: { clickoutside },
  props: {
    allowClear: {
      type: Boolean,
      default: true
    },
    allText: {
      type: String,
      default: "全部"
    },
    noDataText: {
      type: String,
      default: "暂无数据"
    },
    treeData: {
      type: Array,
      default: () => {
        return [];
      }
    },
    dropdownClassName: {
      type: String
    },
    selectOptionsConfig: {
      type: Object,
      default: () => {
        return {
          key: "id",
          value: "value",
          text: "title",
          children: "children"
        };
      }
    },
    maxTagCount: {
      type: Number
    },
    maxTagTextLength: {
      type: Number
    },
    placeholder: {
      type: String,
      default: "请搜索"
    },
    checkAll: {
      type: Boolean,
      default: false
    },
    value: {
      type: Array
    }
  },
  beforeCreate() {
    this.simpleImage = Empty.PRESENTED_IMAGE_SIMPLE;
  },
  destroyed() {
    this.timer && clearInterval(this.timer);
  },
  data() {
    return {
      isOpen: false,
      isCheckAll: this.checkAll,
      isIndeterminateAll: false,
      isClickOutSide: true,
      selectedValueArr: this.value || undefined,
      treeDataList: cloneDeep(this.treeData),
      treeToList: []
    };
  },
  watch: {
    checkAll: {
      handler(newVal) {
        if (newVal) {
          this.timer = setInterval(() => {
            if (this.treeDataList.length > 0) {
              clearInterval(this.timer);
              this.handleCascaderAllItemClick(!newVal);
            }
          }, 30);
        }
      },
      immediate: true
    },
    value: {
      handler(newVal) {
        this.selectedValueArr = newVal;
        this.initDefaultKeys(newVal, this.treeDataList);
        return newVal;
      },
      immediate: true
    },
    treeData(newVal) {
      this.treeListToArrList(newVal[0]);
      this.initDefaultKeys(this.selectedValueArr, newVal);
      this.treeDataList = newVal;
      return newVal;
    }
  },
  created(){
  },
  methods: {
    handleClearAll() {
      this.treeDataList = this.treeData;
      this.isOpen = false;
      this.isCheckAll = false;
      this.isClickOutSide = true;
      this.isIndeterminateAll = false;
      this.updatePostData();
    },
    initDefaultKeys(selectedArr, treeDataList) {
      if (
        selectedArr &&
        selectedArr.length > 0 &&
        treeDataList &&
        treeDataList.length > 0
      ) {
        const treeDataListClone = cloneDeep(treeDataList);
        const treeToListClone = cloneDeep(this.treeToList);
        selectedArr.forEach(item => {
          const curretnItemList = [];
          this.findKeysItem(treeDataListClone[0], item, curretnItemList);
          let currentItem = {};
          if (curretnItemList.length > 0) {
            currentItem = curretnItemList[0];
          }
          if (
            !treeToListClone.find(
              listItem =>
                listItem[this.selectOptionsConfig.value] ===
                currentItem[this.selectOptionsConfig.value]
            )
          ) {
            treeToListClone.push(currentItem);
          }
          currentItem.$checked = true;
          if (
            currentItem[this.selectOptionsConfig.children] &&
            currentItem[this.selectOptionsConfig.children].length > 0
          ) {
            this.setAllDataTreeChecked(
              currentItem[this.selectOptionsConfig.children],
              true
            );
          }
        });
        this.setCheckBoxIndeteriminate(treeDataListClone[0]);
        this.$nextTick(() => {
          this.treeToList = treeToListClone;
          this.treeDataList = treeDataListClone;
        });
      }
    },
    handleCascaderAllItemClick(checkAll) {
      const treeDataListClone = cloneDeep(this.treeDataList);
      // 触发事件的时候v-model中的数据还没有改变，所以要取反
      this.setAllDataTreeChecked(treeDataListClone[0], !checkAll);
      this.clearAllDataActive(treeDataListClone[0]);
      this.setCheckBoxIndeteriminate(treeDataListClone[0]);
      this.treeDataList = treeDataListClone;
      this.updatePostData();
    },
    handleDeselect(value) {
      const treeDataListClone = cloneDeep(this.treeDataList);
      const currentItemList = [];
      this.findKeysItem(treeDataListClone[0], value, currentItemList);
      let currentItem = {};
      if (currentItemList.length > 0) {
        currentItem = currentItemList[0];
      }
      currentItem.$checked = false;
      currentItem.$active = false;
      if (
        currentItem[this.selectOptionsConfig.children] &&
        currentItem[this.selectOptionsConfig.children].length > 0
      ) {
        this.setAllDataTreeChecked(
          currentItem[this.selectOptionsConfig.children],
          false
        );
      }
      this.setCheckBoxIndeteriminate(treeDataListClone[0]);
      this.treeDataList = treeDataListClone;
      this.updatePostData();
    },
    handleCheckClick(e, item, index, levelIndex) {
      const treeDataListClone = cloneDeep(this.treeDataList);
      const childrenTag = this.selectOptionsConfig.children;
      const valueTag = this.selectOptionsConfig.value;
      const currentItemList = [];
      this.findKeysItem(treeDataListClone[0], item[valueTag], currentItemList);
      let currentItem = {};
      if (currentItemList.length > 0) {
        currentItem = currentItemList[0];
      }
      e.stopPropagation();
      e.cancelBubble = true;
      const checked = e.target.checked;
      if (!currentItem.$active && levelIndex !== treeDataListClone.length - 1) {
        // 清空所有选中状态
        this.clearAllDataActive(treeDataListClone[0]);
      }
      if (currentItem[childrenTag] && currentItem[childrenTag].length > 0) {
        // 可展开
        if (!currentItem.$active) {
          const nextIndex = levelIndex + 1;
          if (treeDataListClone[nextIndex]) {
            treeDataListClone.splice(nextIndex);
          }
        }
      } else {
        // 不可展开
        const nextIndex = levelIndex + 1;
        if (treeDataListClone[nextIndex]) {
          treeDataListClone.splice(nextIndex);
        }
      }
      if (currentItem[childrenTag] && currentItem[childrenTag].length > 0) {
        this.setAllDataTreeChecked(currentItem[childrenTag], checked);
      } else {
        currentItem.$checked = checked;
      }
      this.setCheckBoxIndeteriminate(treeDataListClone[0]);
      this.treeDataList = treeDataListClone;
      this.$emit("handleCheckboxChange", {
        event: e,
        item,
        index,
        levelIndex
      });
      this.updatePostData();
    },
    // 单个item点击事件
    handleCascaderItemClick(item, index, levelIndex) {
      const treeDataListClone = cloneDeep(this.treeDataList);
      const childrenTag = this.selectOptionsConfig.children;
      const valueTag = this.selectOptionsConfig.value;
      const currentItemList = [];
      this.findKeysItem(treeDataListClone[0], item[valueTag], currentItemList);
      let currentItem = {};
      if (currentItemList.length > 0) {
        currentItem = currentItemList[0];
      }
      const parentItemsList = [];
      this.findAllParentItems(
        currentItem[valueTag],
        treeDataListClone[0],
        treeDataListClone[0],
        parentItemsList
      );
      parentItemsList.push(currentItem);
      this.clearAllDataActive(treeDataListClone[0]);
      parentItemsList.forEach(activeItem => {
        if (activeItem[childrenTag] && activeItem[childrenTag].length > 0) {
          activeItem.$active = true;
        }
      });
      if (currentItem[childrenTag] && currentItem[childrenTag].length > 0) {
        const nextIndex = levelIndex + 1;
        if (treeDataListClone[nextIndex]) {
          treeDataListClone.splice(nextIndex);
          treeDataListClone[nextIndex] = currentItem[childrenTag];
        } else {
          treeDataListClone.push(currentItem[childrenTag]);
        }
        this.addHideSelectedList(currentItem[childrenTag]);
      } else {
        const nextIndex = levelIndex + 1;
        if (treeDataListClone[nextIndex]) {
          treeDataListClone.splice(nextIndex);
        }
        currentItem.$checked = !currentItem.$checked;
      }
      this.setCheckBoxIndeteriminate(treeDataListClone[0]);
      this.treeDataList = treeDataListClone;
      this.updatePostData();
    },
    handleFocus() {
      this.isOpen = true;
      this.isClickOutSide = false;
    },
    updatePostData() {
      const childrenTag = this.selectOptionsConfig.children;
      const valueTag = this.selectOptionsConfig.value;
      let selectedValueArr = [];
      _getAllItemChecked(this.treeDataList[0]);
      this.$emit("change", selectedValueArr);
      function _getAllItemChecked(treeDataList) {
        let parentItem;
        treeDataList.forEach(item => {
          if (item[childrenTag] && item[childrenTag].length > 0) {
            parentItem = item;
            const currentCheckedAll = [];
            const currentCheckedAllItems = [];
            _getSubChecked(parentItem[childrenTag], currentCheckedAll);
            _getSubCheckedItems(
              parentItem[childrenTag],
              currentCheckedAllItems
            );
            if (currentCheckedAll.every(checkItem => checkItem === true)) {
              if (parentItem[valueTag]) {
                selectedValueArr.push(parentItem[valueTag]);
              }
            } else if (
              currentCheckedAll.some(checkItem => checkItem === true)
            ) {
              currentCheckedAllItems.forEach(selectedItem => {
                if (selectedItem[valueTag]) {
                  selectedValueArr.push(selectedItem[valueTag]);
                }
              });
            }
          } else {
            if (item.$checked) {
              selectedValueArr.push(item[valueTag]);
            }
          }
        });
      }
      function _getSubChecked(itemList, arr) {
        itemList.forEach(item => {
          arr.push(!!item.$checked);
          if (item[childrenTag] && item[childrenTag].length > 0) {
            _getSubChecked(item[childrenTag], arr);
          }
        });
      }
      function _getSubCheckedItems(itemList, arr) {
        itemList.forEach(item => {
          if (item.$checked) {
            arr.push(item);
          } else {
            if (item[childrenTag] && item[childrenTag].length > 0) {
              _getSubCheckedItems(item[childrenTag], arr);
            }
          }
        });
      }
    },
    // 点击组件外部区域
    handleDropDownOutSide() {
      this.isOpen = false;
      this.isClickOutSide = true;
    },
    // 设置当前的选中框的全选等状态
    setCheckBoxIndeteriminate(treeDataList) {
      const childrenTag = this.selectOptionsConfig.children;
      _getAllItemChecked(treeDataList);
      const checkedAllArr = [];
      _getAllItemCheckedAll(treeDataList, checkedAllArr);
      if (checkedAllArr.every(item => item === true)) {
        this.isCheckAll = true;
        this.isIndeterminateAll = false;
      } else if (checkedAllArr.some(item => item === true)) {
        this.isCheckAll = false;
        this.isIndeterminateAll = true;
      } else if (checkedAllArr.every(item => item === false)) {
        this.isCheckAll = false;
        this.isIndeterminateAll = false;
      }
      function _getAllItemCheckedAll(itemList, arr) {
        itemList.forEach(item => {
          arr.push(!!item.$checked);
          if (item[childrenTag] && item[childrenTag].length > 0) {
            _getAllItemCheckedAll(item[childrenTag], arr);
          }
        });
      }
      function _getAllItemChecked(treeDataList) {
        let parentItem;
        treeDataList.forEach(item => {
          if (item[childrenTag] && item[childrenTag].length > 0) {
            parentItem = item;
            _getAllItemChecked(item[childrenTag]);
            const currentCheckedAll = [];
            _getSubChecked(parentItem[childrenTag], currentCheckedAll);
            if (currentCheckedAll.every(checkItem => checkItem === true)) {
              parentItem.$checked = true;
              parentItem.$indeterminate = false;
            } else if (
              currentCheckedAll.some(checkItem => checkItem === true)
            ) {
              parentItem.$checked = false;
              parentItem.$indeterminate = true;
            } else if (
              currentCheckedAll.every(checkItem => checkItem === false)
            ) {
              parentItem.$checked = false;
              parentItem.$indeterminate = false;
            }
          }
        });
      }
      function _getSubChecked(itemList, arr) {
        itemList.forEach(item => {
          arr.push(!!item.$checked);
          if (item[childrenTag] && item[childrenTag].length > 0) {
            _getSubChecked(item[childrenTag], arr);
          }
        });
      }
    },
    // 设置所有选中和非选中
    setAllDataTreeChecked(treeList, checked) {
      const childrenTag = this.selectOptionsConfig.children;
      treeList.forEach(item => {
        item.$checked = checked;
        if (item[childrenTag] && item[childrenTag].length > 0) {
          this.setAllDataTreeChecked(item[childrenTag], checked);
        }
      });
    },
    // 清空所有的active状态
    clearAllDataActive(treeList) {
      const childrenTag = this.selectOptionsConfig.children;
      treeList.forEach(item => {
        item.$active = false;
        if (item[childrenTag] && item[childrenTag].length > 0) {
          this.clearAllDataActive(item[childrenTag]);
        }
      });
    },
    findKeysItem(treeDataList, currentKey, currentItem) {
      const childrenTag = this.selectOptionsConfig.children;
      treeDataList.forEach(item => {
        if (item[this.selectOptionsConfig.value] === currentKey) {
          currentItem.push(item);
        } else {
          if (item[childrenTag] && item[childrenTag].length > 0) {
            this.findKeysItem(item[childrenTag], currentKey, currentItem);
          }
        }
      });
    },
    findAllParentItems(
      currentKey,
      treeDataList,
      originTreeDataList,
      parentItemsList,
      parentItem,
      parentItemsHasKey
    ) {
      if (parentItem && parentItemsHasKey) {
        parentItemsList.unshift(parentItem);
        this.findAllParentItems(
          parentItem[this.selectOptionsConfig.value],
          treeDataList,
          originTreeDataList,
          parentItemsList
        );
      } else {
        this.findKeysAndParentItem(
          currentKey,
          treeDataList,
          originTreeDataList,
          parentItemsList,
          parentItem,
          parentItemsHasKey
        );
      }
    },
    findKeysAndParentItem(
      currentKey,
      treeDataList,
      originTreeDataList,
      parentItemsList,
      parentItem
    ) {
      const childrenTag = this.selectOptionsConfig.children;
      treeDataList.forEach(item => {
        if (item[this.selectOptionsConfig.value] === currentKey && parentItem) {
          this.findAllParentItems(
            parentItem[this.selectOptionsConfig.value],
            originTreeDataList,
            originTreeDataList,
            parentItemsList,
            parentItem,
            true
          );
        } else {
          if (item[childrenTag] && item[childrenTag].length > 0) {
            this.findKeysAndParentItem(
              currentKey,
              item[childrenTag],
              originTreeDataList,
              parentItemsList,
              item
            );
          }
        }
      });
    },
    // 将树形结构数据转换成平面结构
    treeListToArrList(treeList) {
      const arrList = [];
      if (treeList && treeList[0]) {
        treeList.forEach(item => {
          arrList.push(item);
        });
        this.treeToList = arrList;
      }
    },
    addHideSelectedList(treeList) {
      const treeToListClone = Array.from(this.treeToList);
      treeList.forEach(item => {
        if (
          !treeToListClone.find(
            listItem =>
              listItem[this.selectOptionsConfig.value] ===
              item[this.selectOptionsConfig.value]
          )
        ) {
          treeToListClone.push(item);
        }
      });
      this.treeToList = treeToListClone;
    }
  }
};
</script>
<style lang="less">
.gb-ant-select-multiple-cascader {
  .ant-select-dropdown-menu-item {
    display: none;
  }
  .cascader-content-item {
    .checkbox-text {
      padding-left: 8px;
      // font-size: 12px;
      // color: #4a4a4a;
      font-size: 14px;
      color: #565656;
      // padding: 6px 0;
      cursor: default;
      flex: 1;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
      text-align: left;
    }
    &.cascader-content-item-active {
      background-color: rgba(66, 70, 86, 0.05);
      .checkbox-text {
        // color: #1d47aa;
        color: rgba(0, 0, 0, 0.65);
        font-weight: 600;
      }
    }
    // .ant-checkbox-wrapper {
    //   .ant-checkbox-indeterminate {
    //     .ant-checkbox-inner {
    //       &:after {
    //         background-color: #409eff;
    //         left: 48%;
    //       }
    //     }
    //   }
    //   .ant-checkbox-inner {
    //     width: 14px;
    //     height: 14px;
    //     background-color: #fff;
    //     border-color: #7d8292;
    //     &:after {
    //       border-color: #409eff;
    //       left: 20%;
    //     }
    //   }
    // }
  }
  .ant-select-dropdown--multiple {
    min-width: auto !important;
  }
  &.multiple-cascader-outside {
    .ant-select-arrow {
      transform: rotate(180deg);
    }
  }
  .ant-select-arrow {
    margin-top: -8px;
    transition: transform 0.3s;
  }
  .ant-select-dropdown-menu-root {
    display: none;
  }
  .cascader-content-right {
    .right-wrap {
      .ant-checkbox {
        top: 0;
      }
    }
  }
}
</style>
<style lang="less" scoped>
.gb-ant-select-multiple-cascader {
  position: relative;
  .cascader-content-wrap {
    height: 100%;
    .cascader-content-container {
      display: flex;
      flex-direction: row;
      .cascader-content-list {
        list-style: none;
        padding: 0;
        margin: 0;
        // width: 153px;
        min-width: 160px;
        box-sizing: border-box;
        padding: 11px 0;
        max-height: 204px;
        overflow-y: auto;
        border-right: 1px solid rgba(222, 223, 226, 0.3);
        .cascader-content-item {
          padding: 5px 16px;
          margin-top: 5px;
          display: flex;
          flex-direction: row;
          align-items: center;
          line-height: 1.2;
          &:hover {
            background-color: rgba(66, 70, 86, 0.05);
          }
        }
      }
    }
  }
  .cascader-not-content {
    padding: 10px;
    width: 450px;
  }
  /deep/.zoom-leave {
    display: none;
  }
}
</style>
